package demo.hdz.mediacodecdecode;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Point;
import android.hardware.display.IDisplayManager;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentTransaction;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import demo.hdz.mediacodecdecode.customview.FilterAdjustView;
import demo.hdz.mediacodecdecode.customview.IVideoView;
import demo.hdz.mediacodecdecode.customview.VideoGLSurfaceView;
import demo.hdz.mediacodecdecode.customview.VideoGLTextureView;
import demo.hdz.mediacodecdecode.customview.VideoSurfaceView;
import demo.hdz.mediacodecdecode.customview.VideoTextureView;
import demo.hdz.mediacodecdecode.dialog.ListDialog;
import demo.hdz.mediacodecdecode.fileexplorer.FileSelectActivity;
import demo.hdz.mediacodecdecode.fragment.AdjustImageFragment;
import demo.hdz.mediacodecdecode.mainpage.IMainPresenter;
import demo.hdz.mediacodecdecode.mainpage.IMainView;
import demo.hdz.mediacodecdecode.mainpage.MainPresenterImpl;

/**
 * @author hdz
 */
public class MainActivity extends AppCompatActivity implements IMainView, View.OnClickListener {

    private static final String TAG = "MainActivity";

    //public static final String H264_FILE = "carPlay_800x480.h264";//"test_v.mp4";
    //public static final String H264_FILE = "test_v.mp4";
    public String mH264File = "carPlay_800x480.h264";

    public boolean mIsAssets = true;

    private int mScreenWidth = 0;
    private int mScreenHeight = 0;
    private int mVideoWidth = 0;
    private int mVideoHeight = 0;

    private boolean mIsSupportDecode = false;
    private int mRotation = 0;

    private VideoSurfaceView mSurfaceView;
    private VideoTextureView mTextureView;
    private VideoGLSurfaceView mGlSurfaceView;
    private VideoGLTextureView mGlTextureView;
    private int mVideoViewType = 3;

    private LinearLayout mSettingsLayout;
    private EditText mEtLocalFilePath;

    private FilterAdjustView mFilterAdjustView;
    private FloatWindowManage mFloatWindowManage;

    private IMainPresenter mMainPresenter;

    private List<String> mAssetsFiles = null;

    public static Point getResolution() {
        try {
            Method getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class});
            Point displaySize = new Point();
            IWindowManager wm;
            if (Build.VERSION.SDK_INT >= 18) {
                wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
                wm.getInitialDisplaySize(0, displaySize);
            } else if (Build.VERSION.SDK_INT == 17) {
                DisplayInfo di = IDisplayManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"display"})).getDisplayInfo(0);
                displaySize.x = ((Integer) DisplayInfo.class.getDeclaredField("logicalWidth").get(di)).intValue();
                displaySize.y = ((Integer) DisplayInfo.class.getDeclaredField("logicalHeight").get(di)).intValue();
            } else {
                wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
                wm.getRealDisplaySize(displaySize);
            }
            return displaySize;
        } catch (Exception e) {
            Logger.d(e.getMessage());
            return null;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.menu_viewStyle) {
            // 设置渲染方式的对话框
            String[] items = new String[]{"SurfaceView", "TextureView", "GLSurfaceView", "GLTextureView"};
            List<String> langList = Arrays.asList(items);
            ListDialog.run(getSupportFragmentManager(), langList, mVideoViewType, (v, index) -> {
                mVideoViewType = index;
            });
            return true;
        } else if (id == R.id.menu_selectFilter) {
            String[] items = new String[]{"default", "BlackWhite", "normal", "nostalgic", "sharpen"};
            List<String> langList = Arrays.asList(items);
            ListDialog.run(getSupportFragmentManager(), langList, 0, (v, index) -> {

            });
            return true;
        } else if (id == R.id.menu_adjustImage) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.main_layout, new AdjustImageFragment());
            ft.addToBackStack("AdjustImage");
            ft.commitAllowingStateLoss();
            return true;
        } else if (id == R.id.menu_nowAdjust) {
            if (mFilterAdjustView == null) {
                mFilterAdjustView = new FilterAdjustView(getApplicationContext());
                mFilterAdjustView.setCallback(new FilterAdjustView.Callback() {
                    @Override
                    public void onValueChanged(String type, int value) {
                        if (mGlSurfaceView != null) {
                            mGlSurfaceView.setParameter(type, value);
                        }
                    }

                    @Override
                    public void onClose() {
                        mFloatWindowManage.remove(mFilterAdjustView);
                        mFilterAdjustView = null;
                    }
                });

                mFloatWindowManage.show(mFilterAdjustView, 325.0f, 125.0f);
            }
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // requesting to turn the title OFF
        //requestWindowFeature(Window.FEATURE_NO_TITLE);
        // making it full screen
        //getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);

        mMainPresenter = new MainPresenterImpl(this, getApplicationContext());

        initView();

        mFloatWindowManage = new FloatWindowManage(getApplicationContext());

        AssetManager am = getAssets();
        try {
            String[] f = am.list("");
            if (f != null && f.length > 0) {
                mAssetsFiles = Arrays.asList(f);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        showVideo(false);

        getScreenWH();

        //检查是否支持解码
        mIsSupportDecode = mMainPresenter.checkHwDecoder();

        //hideNavigationBar();

        requestPermissions();

        checkVideoCaps();
    }

    private void initView() {
        final RadioButton rBtnFile1 = (RadioButton) findViewById(R.id.rBtnFile1);
        rBtnFile1.setOnClickListener(this);
        RadioButton rBtnFile2 = (RadioButton) findViewById(R.id.rBtnFile2);
        rBtnFile2.setOnClickListener(this);
        RadioButton rBtnLocalFile = (RadioButton) findViewById(R.id.rBtnLocalFile);
        rBtnLocalFile.setOnClickListener(this);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                rBtnFile1.performClick();
            }
        }, 800);

        mSettingsLayout = (LinearLayout) findViewById(R.id.settingsLayout);

        Button btnSelectLocalFile = (Button) findViewById(R.id.btnSelectLocalFile);
        btnSelectLocalFile.setOnClickListener(this);
        mEtLocalFilePath = (EditText) findViewById(R.id.etLocalFilePath);

        findViewById(R.id.btnStartDecode).setOnClickListener(this);

        mSurfaceView = (VideoSurfaceView) findViewById(R.id.surfaceView);
        mTextureView = (VideoTextureView) findViewById(R.id.textureView);
        mGlSurfaceView = (VideoGLSurfaceView) findViewById(R.id.glSurfaceView);
        mGlTextureView = (VideoGLTextureView) findViewById(R.id.glTextureView);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.mMainPresenter.release();
    }

    @Override
    public void onBackPressed() {
        moveTaskToBack(false);
    }

    @Override
    protected void onResume() {
        super.onResume();
        hideNavigationBar();
    }

    private void getScreenWH() {
        DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        // 屏幕宽度（像素）
        mScreenWidth = metric.widthPixels;
        // 屏幕高度（像素）
        mScreenHeight = metric.heightPixels;
        Logger.d("设备屏幕分辨率：" + mScreenWidth + "x" + mScreenHeight);
//        Point point = getResolution();
//        if (point != null) {
//            mScreenWidth = point.x;
//            mScreenHeight = point.y;
//        }
        Logger.d("设备屏幕分辨率：" + mScreenWidth + "x" + mScreenHeight);
    }

    private void showVideo(boolean show) {
        int videoVisible = show ? View.VISIBLE : View.GONE;
        int settingVisible = show ? View.GONE : View.VISIBLE;

        if (mVideoViewType == 1) {
            if (mTextureView != null) {
                VideoTextureView.setSize(mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
                mTextureView.setVisibility(videoVisible);
            }
        } else if (mVideoViewType == 2) {
            if (mGlSurfaceView != null) {
                VideoGLSurfaceView.setSize(mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
                mGlSurfaceView.setVisibility(videoVisible);
            }
        } else if (mVideoViewType == 3) {
            if (mGlTextureView != null) {
                VideoGLTextureView.setSize(mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
                mGlTextureView.setVisibility(videoVisible);
            }
        } else {
            if (mSurfaceView != null) {
                VideoSurfaceView.setSize(mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
                mSurfaceView.setVisibility(videoVisible);
            }
        }
        mSettingsLayout.setVisibility(settingVisible);
    }

    public void onClickStartDecode() {
        Logger.d(TAG + ",onClickStartDecode: " + mScreenWidth + ", " + mScreenHeight + ", " + mVideoWidth + ", " + mVideoHeight);
        if (mScreenWidth <= mScreenHeight) {
            //如果当前视频为宽屏
            if (mVideoWidth > mVideoHeight) {
                mRotation = 270;
            }
        }
        mRotation = 0;
        if (mIsSupportDecode) {
            showVideo(true);

            IVideoView videoView;
            switch (mVideoViewType) {
                case 1:
                    videoView = mTextureView;
                    break;
                case 2:
                    videoView = mGlSurfaceView;
                    break;
                case 3:
                    videoView = mGlTextureView;
                    break;
                case 0:
                default:
                    videoView = mSurfaceView;
                    break;
            }

            mMainPresenter.startDecode(mIsAssets, mH264File, mVideoWidth, mVideoHeight, mRotation, videoView);
        } else {
            showToast("Hardware decoding is not supported.");
        }
    }

    private void showToast(String str) {
        try {
            Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void hideNavigationBar() {
        if (true) {
            return;
        }
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            View decorView = getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                    View.SYSTEM_UI_FLAG_FULLSCREEN |
                    View.SYSTEM_UI_FLAG_IMMERSIVE |
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(uiOptions);
        } else {
            Logger.d("Because the Android version number is lower than 4.4.4, there is no hidden NavigationBar.");
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.rBtnFile1:
                if (isAssetsFileExist("carPlay_800x480.h264")) {
                    mIsAssets = true;
                    mH264File = "carPlay_800x480.h264";
                    mMainPresenter.getVideoSize(this, "carPlay_800x480.h264", true);
                } else {
                    Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.rBtnFile2:
                if (isAssetsFileExist("test_v.mp4")) {
                    mIsAssets = true;
                    mH264File = "test_v.mp4";
                    mMainPresenter.getVideoSize(this, "test_v.mp4", true);
                } else {
                    Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.rBtnLocalFile:
            case R.id.btnSelectLocalFile:
                Intent intent = new Intent(MainActivity.this, FileSelectActivity.class);
                startActivityForResult(intent, 2);
                break;
            case R.id.btnStartDecode:
                onClickStartDecode();
                break;
            default:
                break;
        }
    }

    private boolean isAssetsFileExist(String fileName) {
        if (mAssetsFiles != null && mAssetsFiles.size() > 0) {
            if (mAssetsFiles.contains(fileName)) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == 2) {
                Bundle bundle = data.getExtras();
                mH264File = bundle.get("file").toString();
                mIsAssets = false;
                mMainPresenter.getVideoSize(this, mH264File, false);
                mEtLocalFilePath.setText(mH264File);
            }
        }
    }

    private void requestPermissions() {
        if (Build.VERSION.SDK_INT >= 23) {
            List<String> permissionList = new ArrayList<>();
            if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                permissionList.add(Manifest.permission.RECORD_AUDIO);
            }
            if (permissionList.size() > 0) {
                String[] permissions = permissionList.toArray(new String[permissionList.size()]);
                ActivityCompat.requestPermissions(this, permissions, 0);
            }
        }
    }

    @Override
    public void onGetVideoSize(int width, int height) {
        Logger.d(TAG + ",onGetVideoSize: " + width + "x" + height);
        mVideoWidth = width;
        mVideoHeight = height;
    }

    @Override
    public void onDecodeFinish() {
        showVideo(false);
    }

    @Override
    public void onDecodeFailed() {
        showToast("解码器初始化失败！");
        showVideo(false);
    }

    private void checkVideoCaps() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            String decoderName = "";
            int numCodecs = MediaCodecList.getCodecCount();
            for (int i = 0; i < numCodecs; i++) {
                MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
                if (!info.isEncoder()) {
                    String[] types = info.getSupportedTypes();
                    for (String type : types) {
                        if ("video/avc".equals(type)) {
                            if ("".equalsIgnoreCase(decoderName) || "OMX.google.h264.decoder".equalsIgnoreCase(decoderName)) {
                                decoderName = info.getName();
                            }
                        }
                    }
                }
            }

            try {
                MediaCodec mMediaCodec = MediaCodec.createByCodecName(decoderName);
                MediaCodecInfo codecInfo = mMediaCodec.getCodecInfo();
                MediaCodecInfo.CodecCapabilities caps = codecInfo.getCapabilitiesForType("video/avc");
                MediaCodecInfo.VideoCapabilities videoCaps = caps.getVideoCapabilities();

                TextView tvSupportedWidths = (TextView) findViewById(R.id.tvSupportedWidths);
                tvSupportedWidths.setText(videoCaps.getSupportedWidths().toString());

                TextView tvSupportedHeights = (TextView) findViewById(R.id.tvSupportedHeights);
                tvSupportedHeights.setText(videoCaps.getSupportedHeights().toString());

                mMediaCodec.release();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Toast.makeText(getApplicationContext(), "横屏", Toast.LENGTH_SHORT).show();
            if (mScreenWidth < mScreenHeight) {
                int tmp = mScreenWidth;
                mScreenWidth = mScreenHeight;
                mScreenHeight = tmp;
            }
        } else {
            Toast.makeText(getApplicationContext(), "横屏", Toast.LENGTH_SHORT).show();
            if (mScreenWidth > mScreenHeight) {
                int tmp = mScreenWidth;
                mScreenWidth = mScreenHeight;
                mScreenHeight = tmp;
            }
        }
    }

}
